package cn.iocoder.yudao.module.system.controller.admin.bookcollection;

import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;

import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

import cn.iocoder.yudao.module.system.controller.admin.bookcollection.vo.BookcollectionPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.bookcollection.vo.BookcollectionRespVO;

import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;

import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.system.controller.admin.bookcollection.vo.BookcollectionSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.bookcollection.vo.BookcollectionVO;

import cn.iocoder.yudao.module.system.dal.dataobject.bookcollection.BookcollectionDO;
import cn.iocoder.yudao.module.system.service.bookcollection.BookcollectionService;

// 新增导入
import cn.iocoder.yudao.module.infra.service.file.FileService;
import cn.iocoder.yudao.module.infra.service.file.FileConfigService;
import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient;
import org.springframework.web.multipart.MultipartFile;
import java.util.UUID;
import org.springframework.data.redis.core.StringRedisTemplate;
import lombok.extern.slf4j.Slf4j;
import cn.hutool.core.io.IoUtil;
import org.springframework.transaction.annotation.Transactional;
import cn.iocoder.yudao.module.system.dal.dataobject.book.BookDO;
import cn.iocoder.yudao.module.system.dal.mysql.book.BookMapper;
import cn.iocoder.yudao.module.system.dal.mysql.bookcollection.BookcollectionMapper;
import cn.iocoder.yudao.module.system.dal.mysql.bookcollection.BookcollectionBookMapper;
import cn.iocoder.yudao.module.system.dal.dataobject.bookcollection.BookcollectionBookDO;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.collection.CollUtil;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

@Tag(name = "管理后台 - 绘本集")
@RestController
@RequestMapping("/huiben/bookcollection")
@Validated
@Slf4j
public class BookcollectionController {

    @Resource
    private BookcollectionService bookcollectionService;
    
    // 新增依赖注入
    @Resource
    private FileService fileService;
    
    @Resource
    private FileConfigService fileConfigService;
    
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    
    // 新增依赖注入
    @Resource
    private BookMapper bookMapper;
    
    @Resource
    private BookcollectionMapper bookcollectionMapper;
    
    @Resource
    private BookcollectionBookMapper bookcollectionBookMapper;
    


    @PostMapping("/create")
    @Operation(summary = "创建绘本集")
    @PreAuthorize("@ss.hasPermission('huiben:bookcollection:create')")
    public CommonResult<Long> createBookcollection(@Valid @RequestBody BookcollectionSaveReqVO createReqVO) {
        return success(bookcollectionService.createBookcollection(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新绘本集")
    @PreAuthorize("@ss.hasPermission('huiben:bookcollection:update')")
    public CommonResult<Boolean> updateBookcollection(@Valid @RequestBody BookcollectionSaveReqVO updateReqVO) {
        bookcollectionService.updateBookcollection(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除绘本集")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('huiben:bookcollection:delete')")
    public CommonResult<Boolean> deleteBookcollection(@RequestParam("id") Long id) {
        bookcollectionService.deleteBookcollection(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得绘本集")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('huiben:bookcollection:query')")
    public CommonResult<BookcollectionRespVO> getBookcollection(@RequestParam("id") Long id) {
        BookcollectionDO bookcollection = bookcollectionService.getBookcollection(id);
        return success(BeanUtils.toBean(bookcollection, BookcollectionRespVO.class));
    }

    @GetMapping("/page")
    @Operation(summary = "获得绘本集分页")
    @PreAuthorize("@ss.hasPermission('huiben:bookcollection:query')")
    public CommonResult<PageResult<BookcollectionRespVO>> getBookcollectionPage(@Valid BookcollectionPageReqVO pageReqVO) {
        PageResult<BookcollectionDO> pageResult = bookcollectionService.getBookcollectionPage(pageReqVO);
        return success(BeanUtils.toBean(pageResult, BookcollectionRespVO.class));
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出绘本集 Excel")
    @PreAuthorize("@ss.hasPermission('huiben:bookcollection:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportBookcollectionExcel(@Valid BookcollectionPageReqVO pageReqVO,
              HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<BookcollectionDO> list = bookcollectionService.getBookcollectionPage(pageReqVO).getList();
        // 导出 Excel
        ExcelUtils.write(response, "绘本集.xls", "数据", BookcollectionRespVO.class,
                        BeanUtils.toBean(list, BookcollectionRespVO.class));
    }
    
    @PostMapping("/upload-cover")
    @Operation(summary = "上传临时绘本集封面")
    @PreAuthorize("@ss.hasPermission('huiben:bookcollection:create')")
    public CommonResult<Map<String, String>> uploadCover(@RequestParam("file") MultipartFile file,
                                                        @RequestParam(value = "path", defaultValue = "booklists/temp/") String path) {
        try {
            // 1. 文件重命名：当前时间戳 + 原始文件名
            String originalFilename = file.getOriginalFilename();
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
            String newFilename = timestamp + "_" + originalFilename;
            
            // 2. 构建完整路径
            String fullPath = path + newFilename;
            
            // 3. 上传文件到MinIO（使用正确的FileService方法）
            String fileUrl = fileService.createFile(file.getOriginalFilename(), fullPath, IoUtil.readBytes(file.getInputStream()));
            
            // 4. 生成临时标识
            String tempKey = UUID.randomUUID().toString();
            
            // 5. 存储到Redis，设置5分钟过期时间
            String redisKey = "bookcollection:temp:cover:" + tempKey;
            stringRedisTemplate.opsForValue().set(redisKey, fileUrl, 300, TimeUnit.SECONDS); // 300秒 = 5分钟
            
            // 6. 返回结果
            Map<String, String> result = new HashMap<>();
            result.put("url", fileUrl);
            result.put("tempKey", tempKey);
            
            log.info("文件上传成功: filename={}, path={}, tempKey={}", originalFilename, fullPath, tempKey);
            return success(result);
        } catch (Exception e) {
            log.error("文件上传失败: filename={}, error={}", file.getOriginalFilename(), e.getMessage(), e);
            return CommonResult.error(500, "文件上传失败：" + e.getMessage());
        }
    }
    
    @PostMapping("/complete-create")
    @Operation(summary = "完成绘本集创建")
    @PreAuthorize("@ss.hasPermission('huiben:bookcollection:create')")
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<Boolean> completeCreateBookcollection(@Valid @RequestBody BookcollectionVO createReqVO) {
        try {
            log.info("开始创建绘本集: title={}, tempKey={}, bookIds={}", 
                    createReqVO.getTitle(), createReqVO.getTempKey(), createReqVO.getBookIds());
            
            // 1. 验证封面信息
            String coverUrl = validateAndGetCoverUrl(createReqVO.getTempKey());
            
            // 2. 创建绘本集主记录
            Long collectionId = createBookcollectionRecord(createReqVO.getTitle());
            
            // 3. 验证绘本ID有效性
            validateBookIds(createReqVO.getBookIds());
            
            // 4. 封面图片迁移
            String finalCoverUrl = migrateCoverImage(coverUrl, collectionId);
            
            // 5. 关联绘本与绘本集
            int bookCount = associateBooksWithCollection(collectionId, createReqVO.getBookIds());
            
            // 6. 完善绘本集记录
            updateBookcollectionRecord(collectionId, bookCount, finalCoverUrl);
            
            // 7. 清理Redis中的临时数据
            cleanupTempData(createReqVO.getTempKey());
            
            log.info("绘本集创建成功: collectionId={}, bookCount={}", collectionId, bookCount);
            return success(true);
            
        } catch (Exception e) {
            log.error("绘本集创建失败: title={}, error={}", createReqVO.getTitle(), e.getMessage(), e);
            throw e;
        }
    }
    
    /**
     * 验证并获取封面URL
     */
    private String validateAndGetCoverUrl(String tempKey) {
        if (StrUtil.isEmpty(tempKey)) {
            throw exception(BOOK_COLLECTION_COVER_NOT_EXISTS);
        }
        
        String redisKey = "bookcollection:temp:cover:" + tempKey;
        String coverUrl = stringRedisTemplate.opsForValue().get(redisKey);
        
        if (StrUtil.isEmpty(coverUrl)) {
            throw exception(BOOK_COLLECTION_COVER_NOT_EXISTS);
        }
        
        log.info("获取封面URL成功: tempKey={}, coverUrl={}", tempKey, coverUrl);
        return coverUrl;
    }
    
    /**
     * 创建绘本集主记录
     */
    private Long createBookcollectionRecord(String title) {
        BookcollectionDO bookcollection = new BookcollectionDO();
        bookcollection.setTitle(title);
        bookcollection.setBookCount(0); // 临时设置为0，后续更新
        bookcollection.setCreatedAt(LocalDateTime.now());
        bookcollection.setCoverUrl(""); // 临时设置为空，后续更新
        
        bookcollectionMapper.insert(bookcollection);
        Long collectionId = bookcollection.getId();
        
        log.info("创建绘本集记录成功: collectionId={}, title={}", collectionId, title);
        return collectionId;
    }
    
    /**
     * 验证绘本ID有效性
     */
    private void validateBookIds(List<Long> bookIds) {
        if (CollUtil.isEmpty(bookIds)) {
            throw exception(BOOK_COLLECTION_BOOK_IDS_EMPTY);
        }
        
        List<Long> invalidIds = new ArrayList<>();
        for (Long bookId : bookIds) {
            BookDO book = bookMapper.selectById(bookId);
            if (book == null) {
                invalidIds.add(bookId);
            }
        }
        
        if (!invalidIds.isEmpty()) {
            throw exception(BOOK_COLLECTION_BOOK_NOT_EXISTS, invalidIds);
        }
        
        log.info("验证绘本ID成功: bookIds={}", bookIds);
    }
    
    /**
     * 迁移封面图片
     */
    private String migrateCoverImage(String tempCoverUrl, Long collectionId) {
        String tempPath = null;
        try {
            // 从临时URL中提取文件路径
            tempPath = extractPathFromUrl(tempCoverUrl);
            if (StrUtil.isEmpty(tempPath)) {
                log.error("无法从URL提取文件路径: tempCoverUrl={}", tempCoverUrl);
                throw exception(BOOK_COLLECTION_COVER_MIGRATE_FAILED);
            }
            
            String fileName = getFileNameFromPath(tempPath);
            if (StrUtil.isEmpty(fileName)) {
                log.error("无法从路径提取文件名: tempPath={}", tempPath);
                throw exception(BOOK_COLLECTION_COVER_MIGRATE_FAILED);
            }
            
            // 构建目标路径
            String targetPath = "booklists/" + collectionId + "/" + fileName;
            
            // 从临时路径下载文件内容
            // 获取主文件客户端配置ID
            FileClient masterFileClient = fileConfigService.getMasterFileClient();
            if (masterFileClient == null) {
                log.error("无法获取主文件客户端");
                throw exception(BOOK_COLLECTION_COVER_MIGRATE_FAILED);
            }
            
            log.info("获取主文件客户端成功: configId={}", masterFileClient.getId());
            byte[] fileContent = fileService.getFileContent(masterFileClient.getId(), tempPath);
            if (fileContent == null || fileContent.length == 0) {
                log.error("临时文件内容为空: tempPath={}", tempPath);
                throw exception(BOOK_COLLECTION_COVER_MIGRATE_FAILED);
            }
            
            // 上传到目标路径
             fileService.createFile(fileName, targetPath, fileContent);
            
            log.info("封面迁移成功: collectionId={}, tempPath={}, targetPath={}", 
                    collectionId, tempPath, targetPath);
            
            // 迁移成功后删除临时文件
            deleteTempFile(tempPath);
            
            return targetPath;
            
        } catch (Exception e) {
            log.error("封面迁移失败: collectionId={}, tempCoverUrl={}, tempPath={}, error={}", 
                    collectionId, tempCoverUrl, tempPath, e.getMessage(), e);
            throw exception(BOOK_COLLECTION_COVER_MIGRATE_FAILED);
        }
    }
    
    /**
     * 关联绘本与绘本集
     */
    private int associateBooksWithCollection(Long collectionId, List<Long> bookIds) {
        // 批量插入关联记录
        int insertCount = bookcollectionBookMapper.insertBatch(collectionId, bookIds);
        
        log.info("关联绘本成功: collectionId={}, bookCount={}, insertCount={}", 
                collectionId, bookIds.size(), insertCount);
        return bookIds.size();
    }
    
    /**
     * 更新绘本集记录
     */
    private void updateBookcollectionRecord(Long collectionId, int bookCount, String coverUrl) {
        BookcollectionDO bookcollection = new BookcollectionDO();
        bookcollection.setId(collectionId);
        bookcollection.setBookCount(bookCount);
        bookcollection.setCoverUrl(coverUrl);
        
        bookcollectionMapper.updateById(bookcollection);
        
        log.info("更新绘本集记录成功: collectionId={}, bookCount={}, coverUrl={}", 
                collectionId, bookCount, coverUrl);
    }
    
    /**
     * 清理临时数据
     */
    private void cleanupTempData(String tempKey) {
        String redisKey = "bookcollection:temp:cover:" + tempKey;
        stringRedisTemplate.delete(redisKey);
        
        log.info("清理临时数据成功: tempKey={}", tempKey);
    }
    
    /**
     * 从URL中提取文件路径
     */
    private String extractPathFromUrl(String url) {
        if (StrUtil.isEmpty(url)) {
            return null;
        }
        
        // 根据您的URL格式: http://192.168.158.130:6901/books/booklists/temp/20250808105035_01.png
        // 需要提取: booklists/temp/20250808105035_01.png (不包含bucket名称)
        if (url.contains("/books/")) {
            String path = url.substring(url.indexOf("/books/") + 7); // 去掉 "/books/" 前缀
            log.info("从URL提取路径: url={}, path={}", url, path);
            return path;
        }
        
        log.warn("URL格式不匹配，无法提取路径: url={}", url);
        return null;
    }
    
    /**
     * 从路径中获取文件名
     */
    private String getFileNameFromPath(String path) {
        if (StrUtil.isEmpty(path)) {
            return null;
        }
        
        int lastSlashIndex = path.lastIndexOf("/");
        if (lastSlashIndex == -1 || lastSlashIndex == path.length() - 1) {
            log.warn("路径格式不正确，无法提取文件名: path={}", path);
            return null;
        }
        
        String fileName = path.substring(lastSlashIndex + 1);
        log.info("从路径提取文件名: path={}, fileName={}", path, fileName);
        return fileName;
    }
    
    /**
     * 删除临时文件
     */
    private void deleteTempFile(String tempPath) {
        try {
            if (StrUtil.isNotEmpty(tempPath)) {
                // 获取主文件客户端
                FileClient fileClient = fileConfigService.getMasterFileClient();
                if (fileClient != null) {
                    fileClient.delete(tempPath);
                    log.info("删除临时文件成功: tempPath={}", tempPath);
                } else {
                    log.warn("无法获取文件客户端，跳过删除临时文件: tempPath={}", tempPath);
                }
            }
        } catch (Exception e) {
            // 删除临时文件失败不影响主流程，只记录日志
            log.warn("删除临时文件失败: tempPath={}, error={}", tempPath, e.getMessage());
        }
    }
    

}